﻿/*
 * 漠然@2014年3月14日5:57:17
 * 
 * IO用于答题使用的网络流或者文件流的管理操作
 * 
 */

using System;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;

namespace MuYue.Common
{
    /// <summary>
    /// 网络流
    /// 提供统一的IO流操作的基础
    /// </summary>
    public sealed class MuYueSocket : IDisposable
    {
        #region 私有变量
        /// <summary>
        /// 通信协议标志
        /// </summary>
        private static readonly byte[] flag;

        /// <summary>
        /// 实际用于收发消息的socket
        /// </summary>
        private readonly Socket socket;


        private static Encoding encoding;
        #endregion

        #region 构造函数
        /// <summary>
        /// 初始化协议标志
        /// </summary>
        static MuYueSocket()
        {
            encoding = Encoding.UTF8;
            flag = encoding.GetBytes("MRSOFT");
        }

        /// <summary>
        /// 设置接收信息的超时长度
        /// </summary>
        public int ReceiveTimeout { set { this.socket.ReceiveTimeout = value; } }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="socket">已经建立连接的Socket</param>
        /// <param name="receiveTimeout">接收数据超时设置[ms]</param>
        public MuYueSocket(Socket socket, int receiveTimeout, int sendTimeout = 20000)
        {
            this.socket = socket;
            this.socket.ReceiveTimeout = receiveTimeout;
            this.socket.SendTimeout = sendTimeout;
        }
        #endregion

        #region 接收数据

        /// <summary>
        /// 根据消息收发协议获取实际消息体的长度确定消息边界
        /// </summary>
        /// <returns></returns>
        private long GetBufferLength()
        {
            using (var ms = new MemoryStream())
            {
                var len = 8 + flag.Length;
                var buffer = new byte[len];
                while (len > 0)
                {
                    var iRecv = this.socket.Receive(buffer, len, SocketFlags.None);
                    if (iRecv == 0)
                        throw new Exception("数据读取异常,可能是Socket已经断开了");
                    ms.Write(buffer, 0, iRecv);
                    len -= iRecv;
                }
                buffer = ms.ToArray();
                if (flag.Where((t, i) => t != buffer[i]).Any())
                {
                    return -1;
                }
                return BitConverter.ToInt64(ms.ToArray(), flag.Length);
            }
        }

        /// <summary>
        /// 使用流进行接收数据
        /// </summary>
        /// <param name="ns"></param>
        /// <returns></returns>
        public Stream Recieve(Stream ns = null)
        {
            var length = GetBufferLength();
            if (length < 0)
                throw new Exception("数据长度解析失败,请按照协议发送数据");
            if (ns == null)
            {
                ns = new MemoryStream();
            }

            var maxlen = 1024 * 1024;
            var len = length > maxlen ? maxlen : length;

            var buffer = new byte[len];
            while (length > 0)
            {
                if (length < buffer.Length)
                {
                    buffer = new byte[length];
                }
                var iRecv = this.socket.Receive(buffer);
                if (iRecv == 0)
                    throw new Exception("数据读取异常,可能是Socket已经断开了");
                ns.Write(buffer, 0, iRecv);
                length -= iRecv;
            }
            return ns;
        }

        /// <summary>
        /// 将接收到的数据转化为字符串返回
        /// </summary>
        /// <returns></returns>
        public string RecvStringMessage()
        {
            using (var ns = (MemoryStream)Recieve())
            {
                return encoding.GetString(ns.ToArray());
            }
        }

        #endregion

        #region 发送信息
        /// <summary>
        /// 发送文本消息
        /// </summary>
        /// <param name="data"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public int Send(string strMsg)
        {
            return this.Send(encoding.GetBytes(strMsg));
        }

        /// <summary>
        /// 发送文本消息
        /// </summary>
        /// <param name="data"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public int SendFormat(string data, params object[] args)
        {
            return this.Send(string.Format(data, args));
        }


        public long SendFile(FileStream fs)
        {
            //发送通信协议
            long iSend = this.socket.Send(flag);
            var len = fs.Length;
            iSend += this.socket.Send(BitConverter.GetBytes(len));
            var maxlen = 1024 * 1024;
            len = (len > maxlen) ? maxlen : len;
            var buffer = new byte[len];
            var iRead = fs.Read(buffer, 0, buffer.Length);
            while (iRead > 0)
            {
                iSend += this.socket.Send(buffer, 0, iRead, SocketFlags.None);
                iRead = fs.Read(buffer, 0, buffer.Length);
            }
            return iSend;
        }


        /// <summary>
        /// 实际执行的发送消息
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public int Send(byte[] buffer)
        {
            //发送通信协议
            var iSend = this.socket.Send(flag);
            //发送数据长度
            iSend += this.socket.Send(BitConverter.GetBytes((long)buffer.Length));
            //发送数据
            iSend += this.socket.Send(buffer);
            return iSend;
        }
        #endregion

        #region IDisposable 成员
        /// <summary>
        /// 释放掉占用的资源
        /// </summary>
        public void Dispose()
        {
            this.socket.Close();
            this.socket.Dispose();
        }

        #endregion


    }
}
